#include "common.h"
#include "globals.h"
#include "logger.h"
#include "shared_func.h"
#include "termlist.h"

//-----globals---------
FILE* g_input;
char* fconf="./conf/unitGen.ini";
Globs g;
Stats s;
/*---------------------

idx struture:
rsc_num(uint32_t)
id(int32):res0_fno(int32):res0_foff(uint32_t):res0_len(uint32_t):
res1...


//-------------------*/
void usage() {
  fprintf(stderr, "\n");
  fprintf(stderr, "Project    : %s\n", PROJECT_NAME);
  fprintf(stderr, "BuildDate  : %s\n", BuildDate);
  fprintf(stderr, "Description: %s\n", DESCRIPTION);
  fprintf(stderr, "Usage: ./unitGen\n");
  fprintf(stderr, "\n");
}

static int init_config() {
  IniContext iniContext;
  int ret;
  char* cstr;

  if((ret=iniLoadFromFile(fconf, &iniContext)) != 0) {
    FATAL("error load descriptor file:%s",
	fconf);
    return E_RET;
  }

  set_log_level(iniGetStrValue(NULL, "log_level", &iniContext));

  cstr = iniGetStrValue(NULL, "in_data_path", &iniContext);
  if(cstr == NULL) {
    FATAL("error get value : in_data_path");
    return E_RET;
  }
  strcpy(g.in_data_path,
      cstr);

  cstr = iniGetStrValue(NULL, "out_data_path", &iniContext);
  if(cstr == NULL) {
    FATAL("error get value : out_data_path");
    return E_RET;
  }
  strcpy(g.out_data_path,
      cstr);

  return S_RET;
}

int init() {
  int ret;
  log_init();
  g_log_context.log_level = LOG_DEBUG;
  memset(&g, 0, sizeof(g));
  memset(&s, 0, sizeof(s));
  
  ret = init_config();
  if(ret != S_RET) {
    FATAL("read config error");
    exit(-1);
  }

  return S_RET;
}

void write_idx(uint32_t id, 
    int fid, 
    uint32_t rsc_num, 
    uint32_t* off, 
    uint32_t* len, 
    FILE* ofp) {
  int ret;

  //write id
  ret = fwrite(&id, sizeof(uint32_t), 1, ofp);
  assert(ret == 1);

  for(uint32_t i = 0 ; i < rsc_num ; ++i) {

    DEBUG("id[%u] :fid[%d] off[%u] len[%u]",
	id, fid, off[i], len[i]);

    ret = fwrite(&fid, sizeof(int), 1, ofp);
    assert(ret == 1);

    ret = fwrite(&off[i], sizeof(uint32_t), 1, ofp);
    assert(ret == 1);

    ret = fwrite(&len[i], sizeof(uint32_t), 1, ofp);
    assert(ret == 1);
  }
}

void do_it() {
  int ret;
  char fname[NAME_LEN];
  FILE* fp;
  FILE* ofp;
  int fid = 0;

  uint32_t tlen;
  uint32_t rsc_num;

  uint32_t link_num = 0;

  uint32_t off[MAX_RSC_NUM];
  uint32_t len[MAX_RSC_NUM];

  uint32_t id;

  char* ptr = (char*)malloc(MAX_UNIT_SIZE);
  assert(ptr);

  sprintf(fname, "%s/%s", 
      g.out_data_path,
      UNIT_IDX_NAME);
  ofp = fopen(fname, "w");
  if(ofp == NULL) {
    FATAL("error :fopen [%s] for writing error",
	fname);
    exit(-1);
  }

  //open 1st
  sprintf(fname, "%s/%s.0",
      g.in_data_path,
      UNIT_NAME);
  fp = fopen(fname, "r");
  if(fp == NULL) {
    FATAL("error: fopen [%s] error",
	fname);
    exit(-1);
  }

  //reserve a uint32_t for rsc_num
  uint32_t unused;
  ret = fwrite(&unused, sizeof(uint32_t), 1, ofp);
  assert(ret == 1);

  //reserve a uint32_t for link_num
  ret = fwrite(&unused, sizeof(uint32_t), 1, ofp);
  assert(ret == 1);

  while(1) {

    //read first uint32 (tlen)
    ret = fread(&tlen, sizeof(uint32_t), 1, fp);
    if(ret != 1) {
      if(feof(fp)) {
        NOTICE("finish reading [%s]", fname);
	fclose(fp);
	fid++;
	sprintf(fname, "%s/%s.%d",
	    g.in_data_path,
	    UNIT_NAME,
	    fid);
	fp = fopen(fname, "r");
	if(fp == NULL) {
	  NOTICE("end at[%s]", fname);
	  break;
	}

	ret = fread(&tlen, sizeof(uint32_t), 1, fp);
	assert(ret == 1);

      }
      else assert(0);
    }

    ret = fread(&id, sizeof(uint32_t), 1, fp);
    assert(ret == 1);

    link_num++;

    //read rsc_num
    ret = fread(&rsc_num, sizeof(uint32_t), 1, fp);
    assert(ret == 1);

    //read offs
    ret = fread(off, sizeof(uint32_t), rsc_num, fp);
    assert(ret == (int)rsc_num);

    ret = fread(len, sizeof(uint32_t), rsc_num, fp);
    assert(ret == (int)rsc_num);

    //off transfer
    for(uint32_t j = 0 ; j < rsc_num ; ++j) {
      off[j] = (ftell(fp) + off[j]);
    }

    ret = fread(ptr, tlen, 1, fp);
    assert(ret == 1);

    write_idx(id, fid, rsc_num, off, len, ofp);
  }

  assert(link_num == (id + 1));

  fseek(ofp, 0, SEEK_SET);
  ret = fwrite(&rsc_num, sizeof(uint32_t), 1, ofp);
  assert(ret == 1);

  ret = fwrite(&link_num, sizeof(uint32_t), 1, ofp);
  assert(ret == 1);

}


int main(int argc, char** argv) {
  int ret;

  g_input = stdin;

  ret = init();
  if(ret != S_RET) {
    FATAL("error init system");
    exit(-1);
  }

  if(argc == 2) {
    if(strcmp(argv[1], "-v") == 0 ||
	strcmp(argv[1], "--version") == 0 ||
	strcmp(argv[1], "-h") == 0) {
      usage();
      exit(-1);
    }
    g.mapid = atoi(argv[1]);
  }
  else if(argc == 1) {
    g.mapid = 0;
  }
  else {
    usage();
    exit(-1);
  }
  
  do_it();

  return S_RET;
}
